﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using M3G;

namespace MyTestProject
{
    
    public class TestCamera
    {
  
        [Fact]
        public void TestConstructor()
        {
            var cam = new Camera();
            var tra = new Transform();
            tra.SetIdentity ();

            Assert.Equal(Camera.Generic, cam.Mode);
            Assert.Equal(tra.Matrix, cam.ProjectionTransform.Matrix);
        }

        [Fact]
        public void TestParallel () {
            var cam = new Camera ();
            var fovy        = 45.0f;
            var aspectRatio = 1.3f;
            var near        = 0.1f;
            var far         = 100f;
            cam.SetParallel (fovy, aspectRatio, near, far);

            var exptectedParams = new float[] { fovy, aspectRatio, near, far };
            Assert.Equal (exptectedParams, cam.ProjectionParameters);

            var h = fovy;
            var w = aspectRatio * h;
            var d = far - near;
            var expectedMatrix = new float[] {2/w,   0,    0,  0, 
                                          0, 2/h,    0,  0,
                                          0,   0, -2/d, -(near+far)/d,
                                          0,   0,    0,  1};
            Assert.Equal (expectedMatrix, cam.ProjectionTransform.Matrix);
        }                                                             
                                                             

        [Fact]
        public void TestPerspective()
        {
            var cam = new Camera();
            var fovy        = 45.0f;
            var aspectRatio = 1.3f;
            var near        = 0.1f;
            var far         = 100f;
            cam.SetPerspective (fovy, aspectRatio, near, far);

            var exptectedParams = new float[] { fovy, aspectRatio, near, far };
            Assert.Equal (exptectedParams, cam.ProjectionParameters);

            var h = (float)Math.Tan (fovy / 2.0f);
            var w = aspectRatio * h;
            var d = far - near;
            var expectedMatrix = new float[] {1/w, 0  ,  0           ,  0,
                                        0, 1/h,  0           ,  0,
                                        0, 0  , -(near+far)/d, -2*near*far/d,
                                        0, 0  , -1           ,  0};
            Assert.Equal (expectedMatrix, cam.ProjectionTransform.Matrix);
        }

        [Fact]
        public void TestScreen()
        {
            var cam = new Camera();
            var x = 0;
            var y = 1;
            var width = 640;
            var height = 480;
            cam.SetScreen(x, y, width, height);

            var expectedParams = new float[]{x, y, width, height};
            Assert.Equal (expectedParams, cam.ProjectionParameters);

            var w = (float)width;
            var h = (float)height;
            var tx = -(2 * x + width) / (float)width;
            var ty = -(2 * y + height) / (float)height;
            var expectedMatrix = new float[] {2/w,   0,   0, tx,
                                          0, 2/h,   0, ty,
                                          0,   0,  -1,  0,
                                          0,   0,   0,  1};
            Assert.Equal (expectedMatrix, cam.ProjectionTransform.Matrix);
        }

        [Fact]
        public void TestGeneric()
        {
            var cam = new Camera();
            var tra = new Transform();
            tra.Matrix = new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
            cam.SetGeneric(tra);

            Assert.Equal(Camera.Generic, cam.Mode);

            var expected = new float[] {1,2,3,4,
                                        5,6,7,8,
                                        9,10,11,12,
                                        13,14,15,16};
            Assert.Equal (expected, cam.ProjectionTransform.Matrix);
        }

        [Fact]
        public void TestDuplicate () {
            var cam = new Camera ();
            cam.SetParallel (45.0f, 1.3f, 0.1f, 100f);
            cam.UserID = 100;

            var grp = new Group ();
            grp.AddChild (cam);

            var dup = (Camera)cam.Duplicate ();

            Assert.Equal (null, dup.Parent);
            Assert.Equal (cam.ProjectionParameters, dup.ProjectionParameters);
            Assert.Equal (cam.ProjectionTransform.Matrix, cam.ProjectionTransform.Matrix);
            Assert.Equal (cam.UserID, dup.UserID);
        }

    }
}
